Tomas:
for in
Object.getOwnPropertyNames
取得。getOwnPropertySymbols
)Lai:
日安:
Object.prototype.toString(..)方法
。mango:
chris:
XXX.constructor.name
也可以看型別kai:
Andy:
Henry
Object.prototype.toString.call
得知[[Class]]
屬性Jason
Object.prototype.toString().call()``來抓到
[[class]]`是哪個型別Tony:
Jimmy
最常用的幾個 natives:
這些 natives 實際上是內建函式,確實可以被當作一個原生建構器,但建構出來的東西可能與你想像的不同:
var a = new String("abc");
typeof a; //Object
a instanceof String //true
Object.prototype.toString.call(a); // [object String]
建構式形式所創建的結果,是一個包裹了基型值的物件包裹器。typeof 顯示出這些物件,並非他們自己的特殊型別,他們是 object 的子型別。
重點是 new String("abc")
建立了一個字串包裹器物件,包裹了abc
,而非基型值本身。
typeof 為"object"
的那些值,會額外標示有一個內部的[[Class]]
特性。這個特性無法直接被取用,但可借取Object.prototype.toString(..)
方法,來間接揭露此特性。
Object.prototype.toString.call(null);
// "[Object Null]"
Object.prototype.toString.call(undefined);
// "[Object Undefined]"
多數情況,內部的 Class 值,會對應到該值關聯的原生建構式中,但也有例外狀況,像是建構式 Null() 和 Undefined() 都不存在,但儘管如此,顯露的還是 "Null" 和 "Undefined"。
相對於其他簡單基型值,像是 string、number、boolean,實際上會有其他行為的涉入。
物件包裹器具有非常重要的用途,基本型別值沒有特性或方法,所以要存取length
或toString
,會需要包裹基型值的物件包裹器。
在跑 for
迴圈的時候,最好的方法可能是讓值有物件的形式,但實際上程式會執行得更慢,最好是讓自動封裝的動作隱含的發生,換句話說就是永遠不要使用原生建構式,而使用字面形式的基本型別值。
假設真的要使用原生建構式,有幾個陷阱:
var a = new Boolean(false);
if(!a) {
console.log("Oops!"); //永遠都不會執行
}
建立一個包在 false 值的物件包裹器,但物件本質還是 truthly。
如果要手動封裝一個 Object,可以使用 Object(...)函式(不帶new)。
想要取出其底層的基本型別值,可以使用valueof()
方法。
var myName = new String('Jason');
var weight = new Number(96);
var isHenry = new Boolean(true);
myName.valueOf();//"Jason"
weight.valueOf();//96
isHenry.valueOf();//true
typeof myName.valueOf(); //"string"
typeof weight.valueOf(); //"number"
typeof isHenry.valueOf(); //"boolean"
解封裝的動作也可能隱含的發生,會造成強制轉型:
var myName = new String('Jason');
var sumEmpty = myName + "";
//sumEmpty擁有解封後的基本型別值 "Jason"
// 「myName +」 就是 「myName.valueOf() +」
typeof myName;//"object"
typeof sumEmpty;//"string"
最偏好的方式是使用字面表示來建立基本型別值,這些字面形式的值會與建構式形式所創建的物件相同。
length
被設定為所指定的那個數值。插槽中沒有明確的值,意味著陣列中的插槽會是undefined
。Date().getTime()
方法。message
特性,通常最好是做錯誤物件上呼叫toString
方法,已取得格式化方便閱讀的錯誤訊息。const test1 = Symbol("hello");
const test2 = Symbol("hello");
console.log(test1 === test2); //false
//Tomas
// Tomas 的範例
const obj = {};
const a = Symbol("a");
const b = Symbol("b"); //key 值相同
const c = Symbol("b"); //key 值相同
obj[a] = 'Hello';
obj[b] = 'World';
obj[c] = 'yo!';
const objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(obj[objectSymbols[1]]); // "World"
console.log(obj[objectSymbols[2]]); // "yo!"
// Turtle 的範例
var info = {
name:'Jason',
[Symbol('description')]:'CSS很強',
};
var otherInfo = {
[Symbol('description')]:'很愛性騷擾同事'
};
var Person = Object.assign({},info,otherInfo);
//{name: "Jason",
//Symbol(description): "CSS很強",
//Symbol(description): "很愛性騷擾同事"}
Person[Object.getOwnPropertySymbols(Person)[0]]
// Tomas 的範例
//
Symbol("foo") !== Symbol("foo")
const foo = Symbol()
const bar = Symbol()
typeof foo === "symbol"
typeof bar === "symbol"
let obj = {}
obj[foo] = "foo"
obj[bar] = "bar"
JSON.stringify(obj) // {}
Object.keys(obj) // []
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [ foo, bar ]
每個原生建構式都有自己的prototype
,而這些方法不會直接修改字串,修改動作會從現有的值建立出一個新的值。
Function.prototype
是空的函式,RegExp.prototype
是空的正規表達式,Array.prototype
是空的陣列,這使得他們適合拿來做預設值,可以給尚未擁有適當型別值的變數。
副作用:當設預設值重新創建,會耗費記憶體和 CPU。
const test1 = Symbol("hello");
const test2 = Symbol("hello");
console.log(test1 === test2); //false
Array.from({length: 10}).map((_,index) => index);
//創建某個長度的陣列
var range = Array.from({length: 10})
for (x of range) {
console.log('here')
}
var configObject = {}
Array.prototype.push.call(configObject, "new element")
configObject // {0: "new element", length: 1}
Array.from(configObject) // ["new element"]
字面形式 不用 new
用 new
參數 注意事項 |Array|
[]
|沒差|沒差|1.Array.legnth 2.元素
|Object|{}
|封裝成Object
|幾乎用不到|要封裝的資料
|Function|function(){}
,()=>{}
|要執行的程式碼|別用|要執行的 code|別用來當作 eval()|
|RegExp|/(?:)/|沒差|沒差|正規表達式
|Date|x|別用,不同的 browser 不同結果|常用|指定日期 空參數:回傳現在|ES5:Date.now()
|Error|x|沒差|沒差|變成 error.message
|Symbol|x|正常使用|Uncaught TypeError
|要變 Symbol 的值
- 沒差指的是「有用
new
和不用new
」的差別- 來源自 Chris